package com.cctc.juc.demo.Bitc.Fjuctools.CCyclicBarrier;

import java.util.Random;
import java.util.concurrent.*;
import java.util.concurrent.atomic.AtomicInteger;

public class CyclicBarrierDemo {

    /**
     * 线程间通信方式之使用 CyclicBarrier 循环屏障：多个任务线程之间需要相互等待，直到达到某个 [屏障点]，才能继续执行后续的操作。
     * CyclicBarrier [循环屏障] 是一个常用的线程同步工具，其功能相当于一个屏障点，通过它可以实现多个任务线程之间相互等待，只有当每个任务线程都准备就绪后，才能继续执行各自后续的操作。
     * 核心方法：
     * - public CyclicBarrier(int parties);
     * - public CyclicBarrier(int parties, Runnable barrierAction);
     * - public int await() throws InterruptedException, BrokenBarrierException;
     * - public int await(long timeout, TimeUnit unit) throws InterruptedException, BrokenBarrierException, TimeoutException;
     * 使用步骤：
     * 1）调用构造器，创建 [循环屏障]，指定 CyclicBarrier 的 parties（参与者）数量，例如 2 个;
     * 2）每当一个线程准备就绪时，调用 CyclicBarrier.await() 方法，进行自我等待，等待计数器的值变为 2（所有线程全部准备就绪）时被唤醒，继续执行各自后续的操作。
     * CyclicBarrier 与 CountDownLatch 的异同点：
     * 1. 相同点：二者都用于控制执行线程的数量达到某个临界点时再继续向下执行。
     * 2. 不同点：
     * 1）CountDownLatch 控制的是父线程与并发子任务线程之间的同步关系；而 CyclicBarrier 控制的是各个并发子任务线程之间的同步关系。
     * - CountDownLatch 由父线程调用 await() 方法进行自我阻塞，等到所有并发子任务线程执行完成之后被唤醒，再继续向下执行。
     * - CyclicBarrier 由每个并发子任务线程调用 await() 方法进行自我阻塞，等到所有并发子任务线程都到达某个 [屏障点]（（所有线程全部准备就绪））后，再各自继续向下执行。
     * 2）CountDownLatch 的计数器只能使用一次；而 CyclicBarrier 的计数器可以使用 reset() 方法进行重置，循环使用，如果计算发生错误，可以重置计数器让线程重新执行一次，可以处理更加复杂的并发计算场景。
     */

    private static CyclicBarrier cyclicBarrier = new CyclicBarrier(2, () -> {
        System.out.println("所有线程到达 CyclicBarrier 屏障点，优先执行 CyclicBarrier 回调方法...");
    });
    private static final AtomicInteger index = new AtomicInteger(0);
    private static final Random random = new Random();

    public static void main(String[] args) {
        ExecutorService executorService = Executors.newFixedThreadPool(10, r -> new Thread(r, "worker-thread-" + index.incrementAndGet()));
        for (int i = 0; i < 10; i++) {
            try {
                TimeUnit.SECONDS.sleep(1);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
            executorService.execute(() -> {
                try {
                    TimeUnit.SECONDS.sleep(random.nextInt(3));
                    System.out.println(Thread.currentThread().getName() + " 线程，等待其他线程到达 CyclicBarrier 屏障点...");
                    cyclicBarrier.await();

                    System.out.println(Thread.currentThread().getName() + " 线程被唤醒, 继续向下执行...");
                } catch (InterruptedException | BrokenBarrierException e) {
                    throw new RuntimeException(e);
                }
            });
        }
        executorService.shutdown();
    }

}
